package wiki.xsx.jg.core;

import wiki.xsx.jg.log.Logger;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Set;

/**
 * Java文件生成器
 */
public class FileGenerator {

    /**
     * 生成Java文件
     * @param tableNames 表名，多个逗号分隔
     * @param driverClassName 数据库驱动名称
     * @param dbUrl 数据库地址
     * @param userName 数据库用户名
     * @param password 数据库密码
     * @param rootPath 包的根路径
     * @param packageName 完整包名，如wiki.xsx.test
     * @throws Exception 异常信息
     */
    public static void run(
            String tableNames,
            String driverClassName,
            String dbUrl,
            String userName,
            String password,
            String rootPath,
            String packageName
    ) throws Exception{
        DatabaseService service = DatabaseAdapter.getServiceInstance(driverClassName, dbUrl, userName, password, tableNames, true);
        service.setEntityInfo();
        for (Entity entity : service.getDatabase().getTableSet()){
            write(rootPath, packageName, entity);
            Logger.info("Create file: " + packageName + "." + titleCase(entity.getName()) + ".java");
        }
    }

    /**
     * 写入文件
     * @param rootPath 包的根路径
     * @param packageName 完整包名，如wiki.xsx.test
     * @param entity 实体类对象
     * @return 返回完整类字符串
     * @throws IOException 异常信息
     */
    private static void write (
            String rootPath,
            String packageName,
            Entity entity
    ) throws IOException{
        StringBuilder path = new StringBuilder(createPackage(rootPath, packageName));
        path.append(File.separator).append(titleCase(entity.getName())).append(".java");
        File file = new File(path.toString());
        if (!file.exists()){
            file.createNewFile();
        }
        try (PrintWriter writer = new PrintWriter(file)){
            writer.write(classCase(packageName, entity));
        }catch (IOException e){
            throw e;
        }
    }

    /**
     * 首字母大写
     * @param str 待转换的字符串
     * @return 返回首字母大写的字符串
     */
    private static String titleCase(String str) {
        if (str!=null&&str.trim().length()>0){
            char[] charArray = str.toCharArray();
            charArray[0] -= 32;
            return String.valueOf(charArray);
        }else{
            return str;
        }
    }

    /**
     * 创建包
     * @param filePath 文件路径(不包含包)
     * @param packageName 完整包名，如wiki.xsx.test
     * @return 返回最终的完整路径
     */
    private static String createPackage(String filePath, String packageName){
        File dir = new File(filePath);
        if (!dir.exists()&&!dir.isDirectory()) {
            dir.mkdir();
        }
        StringBuilder pathBuilder = new StringBuilder(filePath);
        String pathes[] = packageName.split("\\.");
        for (String path : pathes){
            pathBuilder.append(File.separator).append(path);
            File file = new File(pathBuilder.toString());
            if (!file.exists()&&!file.isDirectory()) {
                file.mkdir();
            }
        }
        return pathBuilder.toString();
    }

    /**
     * 完整类字符串
     * @param packageName 完整包名，如wiki.xsx.test
     * @param entity 数据表对象
     * @return 返回完整类字符串
     */
    private static String classCase(String packageName, Entity entity) {
        StringBuilder builder = new StringBuilder();
        builder.append(packageCase(packageName));
        if (entity.getComment().trim().length()>0){
            builder.append("// ").append(entity.getComment()).append("\n");
        }
        builder.append("public class ").append(titleCase(entity.getName())).append(" {\n");
        Set<Field> fieldSet = entity.getColumnSet();
        for (Field field : fieldSet){
            builder.append(fieldCase(field));
        }
        builder.append("\n");
        for (Field field : fieldSet){
            builder.append(setterCase(field.getName(), field.getJavaType()));
            builder.append(getterCase(field.getName(), field.getJavaType()));
        }
        builder.append("}");
        return builder.toString();
    }

    /**
     * 类中的包名字符串
     * @param packageName 完整包名，如wiki.xsx.test
     * @return 返回包名字符串
     */
    private static String packageCase(String packageName) {
        StringBuilder builder = new StringBuilder();
        builder.append("package ").append(packageName).append(";\n\n");
        return builder.toString();
    }

    /**
     * 类中的属性字符串
     * @param field 实体类对象
     * @return 返回属性字符串
     */
    private static String fieldCase(Field field) {
        StringBuilder builder = new StringBuilder();
        if (field.getComment().trim().length()>0){
            builder.append("\t// ").append(field.getComment());
            if (field.getDefaultValue()!=null){
                builder.append(", 默认值：").append(field.getDefaultValue());
            }
        }else{
            if (field.getDefaultValue()!=null) {
                builder.append("\t// ").append("默认值：").append(field.getDefaultValue());
            }
        }
        builder.append("\n\tpublic ").append(getTypeString(field.getJavaType())).append(" ").append(field.getName()).append(";\n");
        return builder.toString();
    }

    /**
     * 类中的set方法字符串
     * @param fieldName 字段名
     * @param type 类型
     * @return 返回set方法字符串
     */
    private static String setterCase(String fieldName, Class<?> type) {
        StringBuilder builder = new StringBuilder();
        builder.append("\tpublic void set").append(titleCase(fieldName))
                .append("(").append(getTypeString(type)).append(" ").append(fieldName).append(") {\n")
                .append("\t\tthis.").append(fieldName).append(" = ").append(fieldName).append(";\n")
                .append("\t}\n");
        return builder.toString();
    }

    /**
     * 类中的get方法字符串
     * @param fieldName 字段名
     * @param type 类型
     * @return 返回get方法字符串
     */
    private static String getterCase(String fieldName, Class<?> type) {
        StringBuilder builder = new StringBuilder();
        builder.append("\tpublic ").append(getTypeString(type)).append(" get").append(titleCase(fieldName))
                .append("() {\n")
                .append("\t\treturn this.").append(fieldName).append(";\n")
                .append("\t}\n");
        return builder.toString();
    }

    /**
     * 获取对应的类型
     * @param type 类型
     * @return 返回对应类型字符串
     */
    private static String getTypeString(Class<?> type) {
        StringBuilder builder = new StringBuilder();
        builder.append(type.getSimpleName());
        return builder.substring(builder.lastIndexOf(".")+1);
    }
}
